import time
import dash
from dash import html, dcc, Patch
import feffery_antd_components as fac
import feffery_utils_components as fuc
from feffery_dash_utils.style_utils import style
from dash.dependencies import Input, Output, State, ALL, MATCH

# 自定义题目生成函数
from llm import llm_generate_questions
from flask import Flask

server = Flask(__name__)
app = dash.Dash(
    __name__,
    title="AI在线出题工具",
    suppress_callback_exceptions=True,
    server=server,
    update_title=None,
)

app.layout = html.Div(
    [
        # 全局消息提示
        fac.Fragment(id="global-message"),
        fuc.FefferyDiv(
            [
                fac.AntdSpace(
                    [
                        fac.AntdCenter(
                            fac.AntdSpace(
                                [
                                    html.Img(
                                        src="assets/logo.svg",
                                        height=48,
                                        style=style(display="block"),
                                    ),
                                    fac.AntdText(
                                        "AI在线出题工具",
                                        style=style(
                                            fontFamily="Microsoft YaHei",
                                            fontSize=42,
                                            background="linear-gradient(45deg,#2f78fe,#ece6fe)",
                                            **{
                                                "-webkit-background-clip": "text",
                                                "-webkit-text-fill-color": "transparent",
                                            },
                                        ),
                                    ),
                                ]
                            )
                        ),
                        fac.AntdSpace(
                            [
                                fac.AntdText(
                                    "小提示：系统将根据您输入的领域关键词、难度及出题数量，基于大模型生成对应的若干选择题",
                                    type="secondary",
                                ),
                                fac.AntdRow(
                                    [
                                        fac.AntdCol(
                                            fac.AntdFormItem(
                                                fac.AntdInput(
                                                    id="questions-keyword",
                                                    placeholder="请输入领域关键词，如：Python编程",
                                                    # value="国际近现代史",
                                                    size="large",
                                                    autoComplete="off",
                                                ),
                                                label="领域关键词",
                                                layout="vertical",
                                                style=style(margin=0),
                                            ),
                                            span=10,
                                        ),
                                        fac.AntdCol(
                                            fac.AntdFormItem(
                                                fac.AntdSelect(
                                                    id="questions-level",
                                                    options=[
                                                        {
                                                            "label": level,
                                                            "value": level,
                                                        }
                                                        for level in [
                                                            "简单",
                                                            "中等",
                                                            "困难",
                                                        ]
                                                    ],
                                                    allowClear=False,
                                                    value="中等",
                                                    size="large",
                                                ),
                                                label="难度系数",
                                                layout="vertical",
                                                style=style(margin=0),
                                            ),
                                            span=5,
                                        ),
                                        fac.AntdCol(
                                            fac.AntdFormItem(
                                                fac.AntdSelect(
                                                    id="questions-count",
                                                    options=[
                                                        {
                                                            "label": i,
                                                            "value": i,
                                                        }
                                                        for i in range(1, 11)
                                                    ],
                                                    allowClear=False,
                                                    value=5,
                                                    size="large",
                                                ),
                                                label="出题数量",
                                                layout="vertical",
                                                style=style(margin=0),
                                            ),
                                            span=5,
                                        ),
                                        fac.AntdCol(
                                            fac.AntdButton(
                                                "出题",
                                                id="generate-questions",
                                                type="primary",
                                                autoSpin=True,
                                                loadingChildren="出题中",
                                                block=True,
                                                size="large",
                                            ),
                                            span=4,
                                        ),
                                    ],
                                    align="bottom",
                                    gutter=5,
                                ),
                                fac.AntdSkeleton(
                                    html.Div(
                                        fac.AntdAlert(
                                            type="info",
                                            message="请在完善各条件后再进行出题",
                                            showIcon=True,
                                            closable=True,
                                        ),
                                        id="questions-container",
                                        style=style(minHeight=50),
                                    ),
                                    active=True,
                                    listenPropsMode="include",
                                    includeProps=[
                                        "questions-container.children",
                                    ],
                                ),
                            ],
                            size="small",
                            direction="vertical",
                            style=style(width="100%"),
                        ),
                    ],
                    size="small",
                    direction="vertical",
                    style=style(width="100%"),
                )
            ],
            shadow="always-shadow-light",
            style=style(
                width=800,
                minHeight=500,
                borderRadius=12,
                border="1px solid #d9d9d9",
                background="white",
                margin="0 auto",
                padding=24,
            ),
        ),
    ],
    style=style(paddingTop=100),
)


@app.callback(
    Output("questions-container", "children"),
    Output("generate-questions", "loading"),
    Input("generate-questions", "nClicks"),
    State("questions-keyword", "value"),
    State("questions-level", "value"),
    State("questions-count", "value"),
    prevent_initial_call=True,
)
def generate_questions(nClicks, keyword, level, n):
    """处理新的领域题目生成"""

    if keyword and level and n:
        # 调用大模型按要求生成选择题
        questions = llm_generate_questions(
            user_prompt=f"领域：{keyword} 难度：{level}", n=n
        )
        print("questions", questions)

        return [
            [
                fac.AntdRibbon(
                    html.Div(
                        [
                            # 当前已生成问题数据缓存
                            dcc.Store(id="questions-cache", data=questions),
                            # 答题统计
                            fac.AntdDescriptions(
                                [
                                    fac.AntdDescriptionItem(
                                        fac.AntdText(
                                            "0 / {}".format(n),
                                            id="completed-questions-count",
                                        ),
                                        label="已答题数量",
                                    ),
                                    fac.AntdDescriptionItem(
                                        fac.AntdText(
                                            "0%",
                                            id="correct-rate",
                                        ),
                                        label="正确率",
                                    ),
                                ],
                                bordered=True,
                                column=2,
                                size="small",
                                labelStyle={
                                    "fontWeight": "bold",
                                    "textAlign": "center",
                                },
                                contentStyle={"textAlign": "center"},
                            ),
                        ],
                        style=style(padding="40px 0 20px 0"),
                    ),
                    text="答题统计",
                    placement="start",
                ),
                fac.AntdSpace(
                    [
                        fac.AntdSpace(
                            [
                                fac.AntdText(
                                    f"题目{i+1}",
                                    style=style(
                                        borderLeft="3px solid #40a9ff",
                                        paddingLeft=5,
                                        fontSize=15,
                                    ),
                                ),
                                fac.AntdText(
                                    question["question"],
                                ),
                                fac.AntdCheckCardGroup(
                                    fac.AntdRow(
                                        [
                                            fac.AntdCol(
                                                fac.AntdCheckCard(
                                                    choice + "：" + question[choice],
                                                    value=choice,
                                                    style=style(
                                                        width="100%",
                                                        boxSizing="border-box",
                                                    ),
                                                ),
                                                span=12,
                                            )
                                            for choice in list("ABCD")
                                        ],
                                        gutter=[5, 5],
                                    ),
                                    id={"type": "question", "index": i},
                                    style=style(
                                        width="calc(100% - 5px)",
                                        border="2px dashed transparent",
                                        borderRadius=8,
                                        padding=3,
                                        boxSizing="border-box",
                                    ),
                                ),
                                fac.AntdCollapse(
                                    fac.AntdParagraph(
                                        "正确答案：【{}】，解析：{}".format(
                                            question["answer"],
                                            question["answer_explain"],
                                        )
                                    ),
                                    title="本题详解",
                                    isOpen=False,
                                    ghost=True,
                                ),
                            ],
                            direction="vertical",
                            style=style(
                                width="100%",
                                borderBottom="1px dashed #f0f0f0",
                                paddingBottom=8,
                                marginBottom=8,
                            ),
                        )
                        for i, question in enumerate(questions["questions"])
                    ],
                    direction="vertical",
                    style=style(width="100%", maxHeight=500, overflowY="auto"),
                ),
            ],
            False,
        ]

    time.sleep(0.5)

    return [
        fac.AntdAlert(
            type="info",
            message="请在完善各条件后再进行出题",
            showIcon=True,
            closable=True,
        ),
        False,
    ]


@app.callback(
    Output(
        {"type": "question", "index": MATCH},
        "style",
    ),
    Input({"type": "question", "index": MATCH}, "value"),
    State("questions-cache", "data"),
    prevent_initial_call=True,
)
def handle_question_status(choice, questions_cache):
    """处理各题目答题正确、错误状态反馈"""

    p = Patch()

    if questions_cache["questions"][dash.ctx.triggered_id["index"]]["answer"] != choice:
        p["border"] = "2px dashed #ff4d4f"
    else:
        p["border"] = "2px dashed #389e0d"

    return p


@app.callback(
    Output("completed-questions-count", "children"),
    Input({"type": "question", "index": ALL}, "value"),
    State("questions-cache", "data"),
    prevent_initial_call=True,
)
def update_completed_questions_count(choices, questions_cache):
    """实时统计已答题数量"""

    return "{} / {}".format(
        len([c for c in choices if c]),
        len(questions_cache["questions"]),
    )


@app.callback(
    Output("correct-rate", "children"),
    Input({"type": "question", "index": ALL}, "value"),
    State("questions-cache", "data"),
    prevent_initial_call=True,
)
def update_correct_rate(choices, questions_cache):
    """实时统计正确率"""

    return "{}%".format(
        round(
            100
            * sum(
                [
                    int(c == question["answer"])
                    for c, question in zip(choices, questions_cache["questions"])
                ]
            )
            / len(questions_cache["questions"]),
            1,
        )
    )


if __name__ == "__main__":
    # app.run(debug=False)
    app.run_server(host='0.0.0.0', debug=False)
